{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Teil 8 (fortgeführt) - Einleitung für Protokolle\n",
    "\n",
    "### Kontext \n",
    "\n",
    "Nachdem nun Pläne behandelt wurden, wird es jetzt um ein neues Objekt names Protokoll gehen. Ein Protokoll koordiniert eine Sequenz von Plänen und wendet sie auf entfernten Helfern in einem einzigen Durchgang an. \n",
    "\n",
    "Es ist ein Objekt höchster Ebene und beinhaltet die Logik einer komplexen Berechnung auf mehreren verteilten Helfern. Die wichtigste Eigenschaft eines Protokolls ist die Fähigkeit von Helfern gesendet / gesucht / geholt zu werden und schließlich auf festgelegten Helfern angewendet zu werden.  \n",
    "Somit kann ein Nutzer ein Protokoll erstellen und auf einem Helfer in der Cloud bereit stellen. Jeder andere Helfer kann dieses Protokoll dort suchen, herunterladen und bei sich und allen mit ihm verbundenen Helfern anwenden. \n",
    "\n",
    "Im Folgenden können Sie sehen, wie das erreicht wird.\n",
    "\n",
    "Autoren:\n",
    "- Théo Ryffel - Twitter [@theoryffel](https://twitter.com/theoryffel) - GitHub: [@LaRiffle](https://github.com/LaRiffle)\n",
    "\n",
    "Übersetzer:\n",
    "- Jan Moritz Behnken - Github: [@JMBehnken](https://github.com/JMBehnken)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1. Erstellen und Anwenden"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Protokolle werden mit Listen aus `(worker, plan)`-Paaren erstellt. Dabei kann `worker` entweder ein echter Helfer, eine Helfer-Id oder auch ein String eines fiktiven Helfers sein. Der letzte Fall kann verwendet werden, um beim Erstellen zu spezifizieren, dass zwei Pläne beim Anwenden zum selben Helfer gehören (oder auch nicht). `plan` kann entweder einen Plan oder auch einen PointerPlan enthalten."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-03T14:58:57.529360Z",
     "start_time": "2020-04-03T14:58:55.450814Z"
    }
   },
   "outputs": [],
   "source": [
    "import torch as th\n",
    "import syft as sy\n",
    "hook = sy.TorchHook(th)\n",
    "\n",
    "# IMPORTANT: Local worker should not be a client worker\n",
    "hook.local_worker.is_client_worker = False"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Es werden drei unterschiedliche Pläne erstellt und in einem Protokoll vereint. Jeder der Pläne erhöht den Zähler jeweils um eins."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-03T14:58:57.556157Z",
     "start_time": "2020-04-03T14:58:57.531314Z"
    }
   },
   "outputs": [],
   "source": [
    "@sy.func2plan(args_shape=[(1,)])\n",
    "def inc1(x):\n",
    "    return x + 1\n",
    "\n",
    "@sy.func2plan(args_shape=[(1,)])\n",
    "def inc2(x):\n",
    "    return x + 1\n",
    "\n",
    "@sy.func2plan(args_shape=[(1,)])\n",
    "def inc3(x):\n",
    "    return x + 1\n",
    "\n",
    "protocol = sy.Protocol([(\"worker1\", inc1), (\"worker2\", inc2), (\"worker3\", inc3)])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Nun muss das Protokoll noch an die Helfer gebunden werden. Dies wird erreicht mit dem Aufrufen von `.deploy(*workers)`. Dafür werden drei Helfer erstellt."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-03T14:59:00.740374Z",
     "start_time": "2020-04-03T14:59:00.731945Z"
    }
   },
   "outputs": [],
   "source": [
    "bob = sy.VirtualWorker(hook, id=\"bob\")\n",
    "alice = sy.VirtualWorker(hook, id=\"alice\")\n",
    "charlie = sy.VirtualWorker(hook, id=\"charlie\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-03T14:59:07.723253Z",
     "start_time": "2020-04-03T14:59:07.717245Z"
    }
   },
   "outputs": [],
   "source": [
    "workers = alice, bob, charlie\n",
    "\n",
    "protocol.deploy(*workers)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Wie zu erkennen ist, wurden die Pläne gleich an die richtigen Helfer gesendet: das Protokoll wurde verteilt!\n",
    "\n",
    "Dies geschah in zwei Phasen:\n",
    "- zuerst wurden die Helfer-Strings auf die echten Helfer abgebildet\n",
    "- danach wurden die Pläne ihren jeweiligen Helfern übermittelt"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2. Starten eines Protokolls\n",
    "\n",
    "Ein Protokoll zu starten, bedeutet alle seine Pläne der Reihe nach abzuarbeiten. Dafür werden die Eingabe-Daten an den Ort des ersten Planes gesendet. Dieser erste Plan wird auf die Daten angewendet und seine Ausgabe-Daten an den zweiten Plan weiter geleitet. Dies setzt sich so fort.  \n",
    "Das letzte Ergebnis wird zurückgegeben, sobald alle Pläne abgeschlossen sind. Es enthält Pointer auf den Ort des letzten Planes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-03T14:47:52.027435Z",
     "start_time": "2020-04-03T14:47:52.007190Z"
    }
   },
   "outputs": [],
   "source": [
    "x = th.tensor([1.0])\n",
    "ptr = protocol.run(x)\n",
    "ptr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-03T14:47:55.784595Z",
     "start_time": "2020-04-03T14:47:55.771016Z"
    }
   },
   "outputs": [],
   "source": [
    "ptr.get()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Die Eingabe `1.0` durchlief alle drei Pläne und wurde dort jeweils um eins erhöht. Deshalb entspricht die Ausgabe einer `4.0`!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Selbstverständlich können **Protokolle auch mit Pointern** arbeiten."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-03T14:59:26.938028Z",
     "start_time": "2020-04-03T14:59:26.930281Z"
    }
   },
   "outputs": [],
   "source": [
    "james = sy.VirtualWorker(hook, id=\"james\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-03T14:50:26.249563Z",
     "start_time": "2020-04-03T14:50:26.246409Z"
    }
   },
   "outputs": [],
   "source": [
    "protocol.send(james)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-03T14:50:40.845055Z",
     "start_time": "2020-04-03T14:50:40.833664Z"
    }
   },
   "outputs": [],
   "source": [
    "x = th.tensor([1.0]).send(james)\n",
    "ptr = protocol.run(x)\n",
    "ptr"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Wie zu erkennen ist, ist das Ergebnis ein Pointer zu `james`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-03T14:51:07.585106Z",
     "start_time": "2020-04-03T14:51:07.580967Z"
    }
   },
   "outputs": [],
   "source": [
    "ptr = ptr.get()\n",
    "ptr"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-03T14:51:07.944667Z",
     "start_time": "2020-04-03T14:51:07.937170Z"
    }
   },
   "outputs": [],
   "source": [
    "ptr = ptr.get()\n",
    "ptr"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3. Suche nach einem Protokoll\n",
    "\n",
    "In einem realen Projekt kann es gewünscht sein ein Protokoll herunterzuladen und automatisiert auf den Daten der eigenen Helfer anzuwenden:"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Dafür wir ein **nicht verteiltes Protokoll** erstellt und auf einem Helfer bereit gestellt."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-03T14:59:29.864842Z",
     "start_time": "2020-04-03T14:59:29.857820Z"
    }
   },
   "outputs": [],
   "source": [
    "protocol = sy.Protocol([(\"worker1\", inc1), (\"worker2\", inc2), (\"worker3\", inc3)])\n",
    "protocol.tag('my_protocol')\n",
    "protocol.send(james)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-03T14:59:40.266587Z",
     "start_time": "2020-04-03T14:59:40.259952Z"
    }
   },
   "outputs": [],
   "source": [
    "me = sy.hook.local_worker # get access to me as a local worker"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Nun wird eine Suche nach dem Protokoll gestartet."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-03T14:59:42.801689Z",
     "start_time": "2020-04-03T14:59:42.792265Z"
    }
   },
   "outputs": [],
   "source": [
    "responses = me.request_search(['my_protocol'], location=james)\n",
    "responses"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Zurückgegeben wurde ein Pointer auf das Protokoll."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-03T14:59:45.401011Z",
     "start_time": "2020-04-03T14:59:45.394687Z"
    }
   },
   "outputs": [],
   "source": [
    "ptr_protocol = responses[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Wie gewohnt kann der Pointer genutzt werden um das Objekt zu holen:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-03T14:59:47.666296Z",
     "start_time": "2020-04-03T14:59:47.649808Z"
    }
   },
   "outputs": [],
   "source": [
    "protocol_back = ptr_protocol.get()\n",
    "protocol_back"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Von hier wird genau wie in Teil 1. & 2. verfahren."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2020-04-03T15:00:02.273805Z",
     "start_time": "2020-04-03T15:00:02.250359Z"
    }
   },
   "outputs": [],
   "source": [
    "protocol_back.deploy(alice, bob, charlie)\n",
    "\n",
    "x = th.tensor([1.0])\n",
    "ptr = protocol_back.run(x)\n",
    "ptr.get()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Weitere Beispiele mit Protokollen und echten Szenarien sind in Vorbereitung, doch die Möglichkeiten eines solchen Objektes sollten nun schon erkennbar sein!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### PySyft auf GitHub einen Stern geben! \n",
    "\n",
    "Der einfachste Weg, unserer Community zu helfen, besteht darin, die GitHub-Repos mit Sternen auszuzeichnen! Dies hilft, das Bewusstsein für die coolen Tools zu schärfen, die wir bauen. \n",
    "\n",
    "- [Gib PySyft einen Stern](https://github.com/OpenMined/PySyft)\n",
    "\n",
    "### Nutze unsere Tutorials auf GitHub!\n",
    "\n",
    "Wir haben hilfreiche Tutorials erstellt, um ein Verständnis für Federated und Privacy-Preserving Learning zu entwickeln und zu zeigen wie wir die einzelnen Bausteine weiter entwickeln.\n",
    "\n",
    "- [PySyft Tutorials ansehen](https://github.com/OpenMined/PySyft/tree/master/examples/tutorials)\n",
    "\n",
    "\n",
    "### Mach mit bei Slack! \n",
    "\n",
    "Der beste Weg, um über die neuesten Entwicklungen auf dem Laufenden zu bleiben, ist, sich unserer Community anzuschließen! Sie können dies tun, indem Sie das Formular unter [http://slack.openmined.org](http://slack.openmined.org) ausfüllen.\n",
    "\n",
    "### Treten Sie einem Code-Projekt bei! \n",
    "\n",
    "Der beste Weg, um zu unserer Community beizutragen, besteht darin, Entwickler zu werden! Sie können jederzeit zur PySyft GitHub Issues-Seite gehen und nach \"Projects\" filtern. Dies zeigt Ihnen alle Top-Level-Tickets und gibt einen Überblick darüber, an welchen Projekten Sie teilnehmen können! Wenn Sie nicht an einem Projekt teilnehmen möchten, aber ein wenig programmieren möchten, können Sie auch nach weiteren \"einmaligen\" Miniprojekten suchen, indem Sie nach GitHub-Problemen suchen, die als \"good first issue\" gekennzeichnet sind. \n",
    "\n",
    "- [PySyft Projects](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3AProject)\n",
    "- [Good First Issue Tickets](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)\n",
    "\n",
    "### Spenden\n",
    "\n",
    "Wenn Sie keine Zeit haben, zu unserer Codebase beizutragen, aber dennoch Unterstützung leisten möchten, können Sie auch Unterstützer unseres Open Collective werden. Alle Spenden fließen in unser Webhosting und andere Community-Ausgaben wie Hackathons und Meetups! \n",
    "\n",
    " - [OpenMined's Open Collective Page](https://opencollective.com/openmined)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
